/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package edu.yonsei.iwb.smarttv.model;

import com.hp.hpl.jena.rdf.model.InfModel;
import edu.yonsei.iwb.smarttv.jena.ext.*;
import com.hp.hpl.jena.rdf.model.Model;
import com.hp.hpl.jena.rdf.model.ModelFactory;
import com.hp.hpl.jena.rdf.model.Property;
import com.hp.hpl.jena.rdf.model.RDFNode;
import com.hp.hpl.jena.rdf.model.Resource;
import com.hp.hpl.jena.rdf.model.ResourceFactory;
import com.hp.hpl.jena.rdf.model.Statement;
import com.hp.hpl.jena.rdf.model.StmtIterator;
import com.hp.hpl.jena.reasoner.Reasoner;
import com.hp.hpl.jena.reasoner.ReasonerRegistry;
import com.hp.hpl.jena.reasoner.rulesys.GenericRuleReasonerFactory;
import com.hp.hpl.jena.sdb.SDBFactory;
import com.hp.hpl.jena.sdb.Store;
import com.hp.hpl.jena.sdb.StoreDesc;
import com.hp.hpl.jena.sdb.sql.JDBC;
import com.hp.hpl.jena.sdb.sql.SDBConnection;
import com.hp.hpl.jena.sdb.store.DatabaseType;
import com.hp.hpl.jena.sdb.store.LayoutType;
import com.hp.hpl.jena.tdb.TDBFactory;
import com.hp.hpl.jena.util.FileManager;
import com.hp.hpl.jena.vocabulary.OWL;
import com.hp.hpl.jena.vocabulary.RDF;
import com.hp.hpl.jena.vocabulary.RDFS;
import com.hp.hpl.jena.vocabulary.ReasonerVocabulary;
import edu.yonsei.iwb.smarttv.model.measure.WeightModel;
import edu.yonsei.iwb.smarttv.model.measure.WeightModelType;
import edu.yonsei.iwb.smarttv.util.SMARTTVLog;
import java.io.InputStream;
import java.util.Vector;

/**
 *
 * @author Onlyjiny
 */
public class SMARTTVModel {
    
    public static Resource TARGET_CLASS_URI = ResourceFactory.createResource("http://iweb.yonsei.ac.kr/ontologies/smarttv/Media");    
//    public static Resource TARGET_CLASS_URI;
    public static int NUMBER_OF_PATH = 2;
    private Model model;
    
    private MatrixModel matrixModel;
    private WeightModel weightModel;
    private Store store;
    private int ontType = JenaModelType.TDB_MODEL;
    private int weightModelType = WeightModelType.MEMORY;
    
    
    
    public SMARTTVModel(int type) {
        this.ontType = type;
        if (type == JenaModelType.MEMORY_MODEL) {
            this.model = ModelFactory.createDefaultModel();
        } else if (type == JenaModelType.TDB_MODEL) {
            this.model = TDBFactory.createModel(JenaModelType.MODEL_DIR);
        } else if (type == JenaModelType.SDB_MODEL) {
            StoreDesc storeDesc = new StoreDesc(LayoutType.LayoutTripleNodesHash, DatabaseType.Derby);
            JDBC.loadDriverDerby();
            SDBConnection conn = new SDBConnection(JenaModelType.DB_URL, JenaModelType.DB_USER, JenaModelType.DB_PASSWORD);
            this.store = SDBFactory.connectStore(conn, storeDesc);
            this.model = SDBFactory.connectDefaultModel(store);
        }
    }

    public void loadOntology(String fileName) {
        if (this.ontType == JenaModelType.SDB_MODEL) {
            this.store.getTableFormatter().create();
            this.store.getTableFormatter().truncate();
        } else if(this.ontType == JenaModelType.TDB_MODEL) {
            this.model.removeAll();
        }
        InputStream in = FileManager.get().open(fileName);
        model.read(in, null);
        
        //원래 여기서 weight 계산 했었음
        this.initializeWeight(); // Weight 계산하는 메소드
        
//        Resource configuration =  model.createResource();
//        configuration.addProperty(ReasonerVocabulary.PROPruleMode, "forward");
//        configuration.addProperty(ReasonerVocabulary.PROPruleSet,  JenaModelType.INFERENCE_RULE_FILE);
        
//        Reasoner reasoner = GenericRuleReasonerFactory.theInstance().create(configuration);
//        Reasoner owlReasoner = ReasonerRegistry.getOWLMicroReasoner();
        Reasoner rdfsReasoner = ReasonerRegistry.getRDFSReasoner();
        
        
//        InfModel genInfmodel = ModelFactory.createInfModel(reasoner, model);
//        InfModel owlInfmodel = ModelFactory.createInfModel(owlReasoner, model);
        InfModel rdfsInfmodel = ModelFactory.createInfModel(rdfsReasoner, model);
        
//        this.model.add(genInfmodel.getDeductionsModel());
//        this.model.add(owlInfmodel.getDeductionsModel());
        this.model.add(rdfsInfmodel.getDeductionsModel());
        SMARTTVLog.log(SMARTTVLog.DETAIL, "Ontology Loaded.\n");
                
        this.initializeMatrix();
        if (this.ontType == JenaModelType.TDB_MODEL) {
            model.close();
        }
    }
    
    public void setTargetClassURI(String uri){
        TARGET_CLASS_URI = ResourceFactory.createResource(uri);
    }
    
    public void setWeightModelType(int type){
        this.weightModelType = type;
    }
    
    public void makeWeightFile(){
        this.weightModel.writeWeightTableFile();
        // private Hashtable<Property, PropertyWeightSet> weightTable;을 바탕으로 파일 생성하는 메소드 추가
    }

    public int getResourceType(Resource r) {
        StmtIterator si = model.listStatements(r, RDF.type, (RDFNode) null);
        if (si.hasNext()) {
            RDFNode object = si.nextStatement().getObject();
            if (object.equals(OWL.Class) || object.equals(RDFS.Class)) {
                return JenaResourceType.CLASS;
            } else if (object.equals(OWL.ObjectProperty) || object.equals(OWL.DatatypeProperty) || object.equals(RDF.Property)) {
                return JenaResourceType.PROPERTY;
            }
            return JenaResourceType.INSTANCE;
        } else {
            return JenaResourceType.UNDECLARED;
        }
    }

    public Model getJenaModel() {
        if (this.ontType == JenaModelType.TDB_MODEL) {
            this.model = TDBFactory.createModel(JenaModelType.MODEL_DIR);
        }
        this.initializeWeight();
        this.initializeMatrix();
        return this.model;
    }
    
    public Model getRefineJenaModel() {
        if (this.ontType == JenaModelType.TDB_MODEL) {
            this.model = TDBFactory.createModel(JenaModelType.MODEL_DIR);
        }
        Vector<Property> p = new Vector<Property>();
        StmtIterator st = this.model.listStatements(null, RDF.type, OWL.DatatypeProperty);
        while(st.hasNext()){
            Property datatype = st.nextStatement().getSubject().as(Property.class);
            p.add(datatype); 
        }
        Property isDummy = this.model.createProperty("http://iweb.yonsei.ac.kr/ontologies/smarttv/isDummy");
        Property hasUUID = this.model.createProperty("http://iweb.yonsei.ac.kr/ontologies/smarttv/hasUUID");
        Property initDate = this.model.createProperty("http://iweb.yonsei.ac.kr/ontologies/smarttv/film/film__initial_release_date");        
        p.remove(isDummy);
        p.remove(hasUUID);
        p.remove(initDate);
        
        for (int i = 0; i < p.size(); i++) {
            this.model.removeAll(null, p.get(i), (RDFNode) null);
            this.model.removeAll(p.get(i), RDF.type, OWL.DatatypeProperty);
            this.model.removeAll(p.get(i), RDFS.domain, (RDFNode) null);
            this.model.removeAll(p.get(i), RDFS.range, (RDFNode) null);
            this.model.removeAll(p.get(i), RDFS.label, (RDFNode) null);
        }        
        
        this.initializeWeight();
        this.initializeMatrix();
        return this.model;
    }

    public MatrixModel getMatrixModel() {
        this.initializeMatrix();
        return this.matrixModel;
    }

    public WeightModel getWeightModel() {
        this.initializeWeight();
        return this.weightModel;
    }

    private void initializeMatrix() {
        if (this.matrixModel == null) {
            this.initializeWeight();
            this.matrixModel = new MatrixModel();
            this.matrixModel.initializeGraph(this.model, this.weightModel);
            SMARTTVLog.log(SMARTTVLog.DETAIL, "Completed Transformation of Ontology to Matrix.\n");
        }
    }

    private void initializeWeight() {
        if (this.weightModel == null) {
            this.weightModel = new WeightModel(this.model, this.weightModelType);
            SMARTTVLog.log(SMARTTVLog.DETAIL, "Initialized Weight Values.\n" + this.weightModel.toString());
        }
    }
}
